目录
一,前言
不管在什么语言中,对字符串的处理都是必须且重要的,rust中的字符串数据类型关键字是String。
(一)Rust将字符串分类
Rust将字符串分为两种:
1) &str :固定长度字符串(也称字符串字面量)
2) String :可以随意改变其长度。
(二)Rust将字符串 &str和String区别
&str字符串类型存储于栈上,str字符串序列存储于程序的静态只读数据段或者堆内存中。由两部分组成:
1) 指向字符串序列的指针;
2) 记录长度的值。
String类型本质是一个成员变量为Vec<u8>类型的结构体,所以它是直接将字符内容存放于堆中的。由三部分组成:
1) 执行堆中字节序列的指针(as_ptr方法)
2) 记录堆中字节序列的字节长度(len方法)
3) 堆分配的容量(capacity方法)
二,五种声明方式
fn main(){
//1.第一种方式:通过String的new创建一个空的字符串
let mut my_str = String::new();//不能有字符变量
my_str.push_str("my_str"); //为这个空的字符串变量使用push_str方法添加一个值
//2.第二种方式 通过String的from创建一个字符串
let mut my_str2 = String::from("my_str");
my_str2.push_str("2");
//3.第三种方式,直接书写字符串字面量
let mut my_str3 = "my_str3"; // &str
//4.第四种方式 通过to_string把字面量变成一个字符串
let mut my_str4 = "my_str".to_string();
my_str4.push_str("4");
//5.第五种方式 通过with_capacity创建一个带有预先分配的初始缓冲区的空字符串
//如果已知String的最终大小,String::with_capacity则应首选。
let mut my_str5 = String::with_capacity(7);
my_str5.push_str("my_str5");
println!("{} , {} , {} , {} , {}" , my_str , my_str2 , my_str3 , my_str4 , my_str5);
}
console:
my_str , my_str2 , my_str3 , my_str4 , my_str5
三,迭代器
Rust中的字符串不能使用索引访问其中的字符,可以通过bytes和chars两个方法来分别返回按字节和按字符迭代的迭代器
fn iter_f(){
let mut my_str = String::from("my_str");
let mut bytes = my_str.bytes();
let mut chars = my_str.chars();
println!("{:?} , {:?}", bytes , chars);
for c in my_str.bytes() {
println!("{}", c);
}
for c in my_str.chars() {
println!("{}", c);
}
//从字符串中取单个字符
let a = my_str.chars().nth(2);//nth 函数是从迭代器中取出某值的方法,请不要在遍历中这样使用!因为 UTF-8 每个字符的长度不一定相等!
println!("{:?}", a);
}
console:
Bytes(Copied { it: Iter([109, 121, 95, 115, 116, 114]) }) , Chars(['m', 'y', '_', 's', 't', 'r'])
109
121
95
115
116
114
m
y
_
s
t
r
Some('_')
四 ,追加字符串
五种追加字符串: insert,insert_str ,push和push_str,以及迭代器
fn push_f(){
let mut my_str = String::new();
my_str.push_str("my_str");//只能跟字面变量 &str
let mut my_str2 = String::new();
my_str2.push('2');//char
let mut my_str3 = String::from(['3'][0]);//&str ,char(元素类型是这两个就行)
let mut my_str4 = [4][0].to_string();//char ,i32,...
// Ø 连接字符串:String实现了Add<&str>和AddAssign<&str>两个trait,所以可以使用“+”和“+=”来连接字符串
my_str += &my_str2 ;//加&的意思是传入字符串对象的引用,但不释放所有权,为了可以使用使用原来的字符串变量
my_str = my_str + &my_str3;// 两个引用,只能一个引用一个具体对象
// my_str3 = my_str + &my_str3;//值会不能拼接到引用的对象上
//不引用的对象失去所有权,my_str变成了空的字符串变量 borrow of moved value: `my_str`
let mut my_str5 = my_str + &my_str4;
my_str = "my_str".to_string();//依然是String类型,只能赋值String类型
println!("{} , {} , {} , {} , {}" , my_str , my_str2 , my_str3 , my_str4 , my_str5);
}
///迭代器chars追加
fn chars_f(){
//1,把my_str6追加到my_str_7后
let mut my_str6 = String::from("my_str");
let mut my_str_7 = String::from("new");
for c in my_str6.chars() {
my_str_7.push(c);
}
//2,把my_str8补齐8位
let mut my_str8 = String::from("0000");
let len = my_str8.len();
for _ in 0..8-len {
my_str8.push('0');
}
println!("my_str_7:{} , my_str8:{}", my_str_7 , my_str8);
}
/// 插入字符串:insert和insert_str ,在某个下标之前插入
fn insert_f(){
//可以在末尾追加也可以0 - String.len() 之间任何位置插入字符串
let mut my_str = String::from("my_str");
my_str.insert(my_str.len(),'1');//`char` 字符对象下标从0开始
my_str.insert_str(my_str.len(),"2");//`&str`
println!("{} " , my_str );//my_str12
}
fn main(){
push_f();
chars_f();
insert_f();
}
console:
my_str , 2 , 3 , 4 , my_str234
my_str_7:newmy_str , my_str8:00000000
my_str12
五,删除
五种删除字符串:remove、pop、truncate、clear和drain
fn del_f(){
let mut my_str = String::from("my_str");
//usize 删除参数对应下标的字符
// my_str.remove(0);//y_str
//从末尾删除字符
// my_str.pop();//my_st
//删除参数对应下标之后的字符
// my_str.truncate(2);//my_
//清空
// my_str.clear();//有一个空所有权的空对象,这个比较有意思
//删除固定范围内的字符串
let n1 =0;let n2=3;
my_str.drain(n1..n2);// 0..3
println!("{}" , my_str );
}
六,转换 &str < - > String
把String
转换为&str
的代价很小,不过从&str
转换到String
涉及到分配内存。除非必要,没有理由这样做!
//&str --> String
let s1 = "Hello".to_string();
let mut my_str = String::new();
my_str.push_str("my_str");
//String --> &str
let s2:&str = &s1;
let string1 = String::from("abcd");
let result:&str = string1.as_str();
七,替换,查找,批量修改等
只列出部分常用的,如有需求 请看API: https://doc.rust-lang.org/std/primitive.str.html#method.trim
println!("{} ", "".starts_with("a"));
println!("以什么开始 :{} {}",String::from("abc").starts_with("a"), "".starts_with("a"));
println!("以什么结尾 :{} {}",String::from("abc").ends_with("c") , "abc".ends_with("c"));//ends_with<'a, P>(&'a self, pat: P) -> bool
let four: i32 = "4".parse().unwrap();
println!("{} ", four+1);
println!("{} {}", "a".repeat(4) ,String::from("b").repeat(4));//repeat(&self, n: usize) -> String
println!("{} {}", "".is_empty(),String::from("").is_empty());
println!("{} {}", "this is old".replace("old", "new"),String::from("this is old").replace("old", "new"));
let s = "foo foo 123 foo";
println!("{} ", s.replace("foo", "1"));//全部替换
println!("{} ", s.replacen("foo", "1" , 1));//替换几个
let v: Vec<&str> = "1,2,3,4".split(',').collect();//"" == [""]
println!("{:?} ", v);
println!("{} {} {}", " S S ".trim()," S S ".len(), " S S ".trim().len());//去掉的是两边的空格
let s:String = "Hello, world!".chars()
.map(|x| match x {
'!' => '?',
'A'...'Z' => 'X',
'a'...'z' => 'x',
_ => x}
).collect();
println!("{}", s);
console:
aaaa bbbb
true true
this is new this is new
1 1 123 1
1 foo 123 foo
["1", "2", "3", "4"]
S S 5 3
Xxxxx, xxxxx?